<template>
  <span>{{ Math.floor(displayValue) }}</span>
</template>

<script setup lang="ts">
import { ref, watch, onMounted } from 'vue'
defineOptions({
    name: 'NumberRoller'
});
const props = withDefaults(defineProps<{
    target: number,
    duration?: number,
}>(), {
    duration: 2000, 
});
const displayValue = ref(0)

// 缓动函数：easeOutQuad
function easeOutQuad(t:number) {
  return 1 - (1 - t) * (1 - t)
}

function animateCounter(start:number, end:number, duration:number) {
  let startTime:number|null = null

  const step = (timestamp:number) => {
    if (!startTime) startTime = timestamp
    const progress = timestamp - startTime
    const percentage = Math.min(progress / duration, 1)
    const easedPercentage = easeOutQuad(percentage)
    displayValue.value = start + (end - start) * easedPercentage

    if (percentage < 1) {
      requestAnimationFrame(step)
    }
  }

  requestAnimationFrame(step)
}

// 监听 target 变化并重新触发动画
watch(
  () => props.target,
  (newVal, _) => {
    animateCounter(displayValue.value, newVal, props.duration)
  }
)

// 初始动画
onMounted(() => {
  animateCounter(0, props.target, props.duration)
})
</script>

<style scoped>
</style>